package com.config;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.web.client.RestOperations;

import javax.net.ssl.SSLContext;
import java.time.Duration;
import java.util.ArrayList;

@Slf4j
@Setter
@EnableWebSecurity(debug = true)
@Configuration
public class Config extends WebSecurityConfigurerAdapter {
    /**
     * todo  try to add the additonalCheck  from  the openId to verify the user.
     *
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests()
                .antMatchers("/message/**").hasAuthority("SCOPE_message.read")
                .antMatchers("/**").hasAuthority("SCOPE_openid")
                .anyRequest().authenticated()
                .and()
                .formLogin().permitAll() // permit for login page.
                .usernameParameter("username").passwordParameter("password")
                .and()
                .oauth2ResourceServer()
                .jwt();;
    }
    @Bean
    public UserDetailsService userDetailsService(){
        ArrayList<UserDetails> users = new ArrayList<>();
        users.add(User.withUsername("user").password("{bcrypt}$2a$10$Nl8zvMdhS0l22hBR.hAsNuQeMWH0.dgVRC/4.a0ny37SiI2Hbc4iW").roles("USER").build());
        users.add(User.withUsername("user1").password("{bcrypt}$2a$10$6r4WkpfuAZ/k7UnoOwtXo.QsMTO.nBz2wZKtwG63t3VcFQj1BXxqC").roles("POST").build());
       return new InMemoryUserDetailsManager(users);
    }


    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/webjars/**");
    }
    @Value("${jwkSetUri}")
    public String jwkSetUri;
    @Value("${trust-store}")
    private Resource trustStore;

    @Value("${trust-store-password}")
    private String trustStorePassword;

    @Value("${key-store}")
    private Resource keyStore;

    @Value("${key-store-password}")
    private String keyStorePassword;

    @Value("${key-password}")
    private String keyPassword;

    @Bean
    public  SSLContext sslContext(){
        SSLContext sslContext = null;
        try {
            sslContext = new SSLContextBuilder()
                    .loadTrustMaterial(trustStore.getURL(), trustStorePassword.toCharArray()).
                            loadKeyMaterial(keyStore.getURL(), keyStorePassword.toCharArray(), keyPassword.toCharArray())
                    .build();
        } catch (Exception ex) {
            throw new RuntimeException("ssl configuration has problems.: " + ex.getMessage());
        }

        return sslContext;
    }

    @Bean
    public JwtDecoder jwtDecoder(RestTemplateBuilder builder,SSLContext sslContext) {
        log.info("init the JwtDecoder===================================================");
        // TODO Add custom configuration, eg. Proxy, TLS, etc

        SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext);

        HttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(socketFactory)
                .build();
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setHttpClient(httpClient);

        RestOperations rest = builder
                .setConnectTimeout(Duration.ofSeconds(60))
                .setReadTimeout(Duration.ofSeconds(60))
                .requestFactory(()->{return  factory;})
                .build();

        NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.
                withJwkSetUri(jwkSetUri)
                .restOperations(rest).build();
        return jwtDecoder;
    }
}
